<?php
namespace App\Common\Cla\ClaBase\Traits;

use App\Common as com;

trait GoPool {

	private array $_goPool = [];

	private array $_goPoolOfParam = [];

	private array $_goPoolOfUnique = [];

	/**
	 * goPool是否已设置
	 * @param string $poolName 池名
	 * @return bool
	 */
	protected function goPoolIsset( string $poolName ) {
		return isset( $this->_goPool[ $poolName ] );
	}

	/**
	 * goPool设置指定
	 * @param string $poolName 池名
	 * @param mixed $poolValue 数据
	 * @return $this
	 */
	protected function goPoolSet( string $poolName, $poolValue ) {
		$this->_goPool[ $poolName ] = $poolValue;
		//
		return $this;
	}

	/**
	 * 获取池
	 * @param string $poolName 池名
	 * @param \Closure $callback 回调
	 * @param \Closure|null $finishCallbackEvent 回调后事件
	 * @return mixed
	 * @throws
	 */
	protected function goPool( string $poolName, \Closure $callback, \Closure|null $finishCallbackEvent = null ){
		//
		if( ! isset( $this->_goPool[ $poolName ] ) ){
			$data = $callback();
			if( is_object( $data ) ){
				// $this->_goPool[ $poolName ] = \WeakReference::create( $data ); // 使用弱引用，防止引用阻止销毁;
				$this->_goPool[ $poolName ] = $data;
			}else{
				$this->_goPool[ $poolName ] = $data;
			}
			// 执行回调后事件
			if( $finishCallbackEvent instanceof \Closure ){
				call_user_func( $finishCallbackEvent );
			}
		}
		//
		// 弱引用
		if( $this->_goPool[ $poolName ] instanceof \WeakReference ){
			$obj = $this->_goPool[ $poolName ]->get();
			//
			if( $obj === null ){
				throw com\Lib\Err\Exception::makeOfNew( "goPool弱数据不存在({$poolName})", com\Lib\Err\Code::$sysFunExecuteError );
				// 重新初始化
				// return $this->goPool( $poolName, $callback, $finishCallbackEvent );
			}
			//
			return $obj;
		}
		//
		return $this->_goPool[ $poolName ];
	}

	/**
	 * 销毁指定goPool
	 * @param string $poolName 池名
	 * @return bool [true][必返]
	 */
	protected function goPoolUnset( string $poolName ):bool {
		unset( $this->_goPool[ $poolName ] );
		//
		return true;
	}

	/**
	 * @param $paramsMixed
	 * @return string
	 */
	private function goPoolParamAsBuildParamMixedStr( $paramsMixed ):string {
		return is_array( $paramsMixed ) ? implode( '_', $paramsMixed ) : $paramsMixed;
	}

	/**
	 * 获取池(参数唯一，相同参数确认唯一)
	 * @param string $poolName 池名
	 * @param int|string|array $paramsMixed 池参数
	 * @param \Closure $callback 回调 fn( string $poolUniqueId )
	 * @return mixed
	 */
	protected function goPoolParam( string $poolName, $paramsMixed, \Closure $callback ):mixed {
		$paramMixedStr = $this->goPoolParamAsBuildParamMixedStr( $paramsMixed );
		$poolQuote = &$this->_goPoolOfUnique[ $poolName ][ $paramMixedStr ];
		// 检查是否存在 || 检查参数是否一致
		if( ! isset( $poolQuote )){
			$poolQuote = $callback( "{$poolName}{$paramMixedStr}" );
		}
		//
		return $poolQuote;
	}

	/**
	 * 销毁指定goPoolParam
	 * @param string $poolName 池名
	 * @return bool [true][必返]
	 */
	protected function goPoolParamUnSet( string $poolName, $paramsMixed ):bool {
		if( ! array_key_exists( $poolName, $this->_goPoolOfUnique ) ){
			return true;
		}
		//
		$paramMixedStr = $this->goPoolParamAsBuildParamMixedStr( $paramsMixed );
		if( array_key_exists( $paramMixedStr, $this->_goPoolOfUnique[ $poolName ] ) ){
			unset( $this->_goPoolOfUnique[ $poolName ][ $paramMixedStr ] );
		}
		//
		if( empty( $this->_goPoolOfUnique[ $poolName ] ) ){
			unset( $this->_goPoolOfUnique[ $poolName ] );
		}
		//
		return true;
	}

	/**
	 * 获取池(poolName唯一，poolName确认唯一，参数不同时自动销毁上一次的数据)
	 * @param string $poolName 池名
	 * @param int|string|array $paramMixed 池参数 [array]支持一维数组
	 * @param \Closure $callback 回调
	 * @return mixed
	 */
	protected function goPoolUnique( string $poolName, $paramMixed, \Closure $callback ) {
		// ...
		if( is_array( $paramMixed ) ){
			$paramMixedStr = implode( '_', $paramMixed );
		}else if( is_string( $paramMixed ) || is_numeric( $paramMixed ) ){
			$paramMixedStr = $paramMixed;
		}else{
			throw com\Lib\Err\Exception::makeOfNew( '$paramMixed 参数类型错误', com\Lib\Err\Code::$sysFunParamError );
		}
		//
		$poolQuote = &$this->_goPoolOfUnique[ $poolName ];
		// 检查是否存在 || 检查参数是否一致
		if( ! isset( $poolQuote ) || $poolQuote['paramMixedStr'] != $paramMixedStr ){
			$poolQuote['paramMixedStr'] = $paramMixedStr;
			$poolQuote['data'] = $callback();
		}
		//
		return $poolQuote['data'];
	}

	/**
	 * 销毁指定goPoolUnique
	 * @param string $poolName 池名
	 * @return bool [true][必返]
	 */
	protected function goPoolUniqueUnSet( string $poolName ):bool {
		unset( $this->_goPoolOfUnique[ $poolName ] );
		//
		return true;
	}
	
}
